/*
    服务端业务处理模块
*/

#ifndef __M_CSERVER_H__
#define __M_CSERVER_H__
#include"Config.hpp"
#include"Cdata.hpp"
#include<sstream>
#include"../tools/cpp-httplib-master/httplib.h"

extern Hxy_Cloud::DataManager* _data;

namespace Hxy_Cloud
{
    class Server
    {
        private:
        static void Upload(const httplib::Request& req,httplib::Response& res)
        {
            auto ret = req.has_file("file");
            if(ret == false)
            {
                res.status = 400;
                return;
            }
            // 获取上传文件的数据  
            httplib::MultipartFormData file = req.get_file_value("file");
            std::string back_dir = Hxy_Cloud::Config::GetInstance()->GetBackDir();
            std::string realpath = back_dir + Hxy_Cloud::FileUtil(file.filename).FileName();
            Hxy_Cloud::FileUtil fu(realpath);
            fu.SetContent(file.content);    //将上传的文件数据写入到备份文件
            Hxy_Cloud::DataManager dm;  
            Hxy_Cloud::BackUpInfo info(realpath);   //获取备份文件信息
            dm.Insert(info);    //将备份文件信息放到数据管理模块
            return;
        }
        static std::string gettime(const time_t& t)
        {
            std::string tmp = ctime(&t);
            return tmp;
        }
        static void ListShow(const httplib::Request& req,httplib::Response& res)
        {
            //读取所有备份文件
            std::vector<Hxy_Cloud::BackUpInfo> table;
            if(_data->GetAll(&table) == false)
            {
                res.status = 500;
                return;
            }
            std::cout<<"获取展示页面成功 ： "<<table.size()<<std::endl;
            //组织前端代码页面展示
            std::stringstream ss;
            ss<<R"(<!DOCTYPE html><html lang="en"><head>)";
            ss<<R"(<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">)";
            ss<<"<title>Download</title>";
            ss<<R"(</head><body><h1>Download</h1><table>)";
            for(const auto& info : table)
            {
                ss<<"<tr>";
                std::string filename = Hxy_Cloud::FileUtil(info.real_path).FileName();
                ss<<"<td><a href='"<<info.url_path <<"'> "<<filename << "</a></td>";
                std::string time = gettime(info.atime);
                ss<<R"("<td align="right">")"<<time<<"</td>";
                ss<<R"("<td align="right">")"<<info.size / 1024<<"K</td>";
                ss<<"<tr>";
            }
            ss<<R"(</table></body></html>)";
            res.body = ss.str();
            res.status = 200;
            res.set_header("Content-Type","text/html"); 
            return;
        }
        static std::string ETags(const Hxy_Cloud::BackUpInfo& info)
        {
            //ETags ： "filename-size-mtime"
            std::string etag = Hxy_Cloud::FileUtil(info.real_path).FileName();
            etag += "-";
            etag += std::to_string(info.size);
            etag += "-";
            etag += std::to_string(info.mtime);
            return etag;
        }
        static void Download(const httplib::Request& req,httplib::Response& res)
        {
            //获取请求中的下载路径 req.path http://139.9.209.130:8888/download/file1.txt
            std::string path = req.path;
            Hxy_Cloud::BackUpInfo info;
            _data->GetOneByUrl(path,&info);
            //判断需要下载的文件是否需要解压
            if(info.is_pack == true)
            {
                //进行解压，修改备份文件信息，删除压缩包
                Hxy_Cloud::FileUtil fu(info.pack_path);
                fu.UnCompress(info.real_path);
                info.is_pack = false;
                _data->Update(info);
                fu.RemoveFile();
            }   
            //判断是非需要断点续传
            bool retransmit = false;
            std::cout<<"If-Range: "<<req.has_header("If-Range")<<std::endl;
            if(req.has_header("If-Range")) //判断请求的文件是否存在ETags头部字段，存在代表这个文件之前请求过
            {
                //If-Range : 存放文件的唯一标识etag
                std::string old_etag = req.get_header_value("If-Range");
                if(old_etag == ETags(info)) //判断之前的etag是非和现在文件的etag相同 相同则需要重新上传
                {
                    retransmit = true;
                    std::cout<<"retransmit"<<retransmit<<std::endl;
                }
            }
            //将文件信息写入res.body
            Hxy_Cloud::FileUtil(info.real_path).GetContent(&res.body);
            std::cout<<"retransmit"<<retransmit<<std::endl;
            if(!retransmit)
            {
                std::cout<<"进行正常传输\n";
                //设置res的头部字段 ETags ： "filename-size-mtime⼀个能够唯⼀标识⽂件的数据"  
                res.set_header("ETag",ETags(info));
                //Accept-Ranges: bytes 指服务器支持断点续传功能
                res.set_header("Accept-Ranges","bytes");
                //设置文件Content-Type头部字段，用来标记文件需要处理的类型
                res.set_header("Content-Type","application/octet-stream");
                res.status = 200;
            }
            else{
                std::cout<<"进行断点传输\n";
                //在httplib内部已经实现了断点续传功能，只需要把文件body都上传上去 状态码设置206即可
                //上传到的body httplib会将数据读取，使用 std::string body = res.get_header_val("Range"); 
                // 提取的body是一个 bytes=start-end的数据 start表示断点需要读取body的起始位置 end表示读取文件的终止位置

                //设置res的头部字段 ETags ： "filename-size-mtime⼀个能够唯⼀标识⽂件的数据"  
                res.set_header("ETag",ETags(info));
                //Accept-Ranges: bytes 指服务器支持断点续传功能
                res.set_header("Accept-Ranges","bytes");
                //设置文件Content-Type头部字段，用来标记文件需要处理的类型
                res.set_header("Content-Type","application/octet-stream");
                //res.set_header("Content-Range","bytes start-end/fsize"); 手动实现断点续传还需要对Content-Range数据进行设置
                res.status = 206; //206状态码代表进行区间上传
            }   
            return;
        }
        void GetConfTable()
        {
            Hxy_Cloud::Config* conf = Hxy_Cloud::Config::GetInstance();
            _svr_port = conf->GetSvrPort();
            _svr_ip = conf->GetSvrIp();
            _download_perfix = conf->GetDownloadPer();
        }
        public:
        Server()
        {
            GetConfTable();
        }
        bool RunModule()
        {
            _svr.Post("/upload",Upload);
            _svr.Get("/listshow",ListShow);
            _svr.Get("/",ListShow);
            std::string download = _download_perfix + "(.*)";
            _svr.Get(download,Download);
            if(_svr.listen(_svr_ip,_svr_port) == false)
            {
                CloudLog::GetInstance().Fatal(__FILE__,__LINE__,"服务器启动失败！！");
                return false;
            }
            return true;
        }
        private:
        int _svr_port;
        std::string _svr_ip;
        std::string _download_perfix;
        httplib::Server _svr;
    };
}

#endif